﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;
using System.Xml;

namespace SMS
{
    public partial class MainForm : Form
    {
		#region Fields (16) 

        BindingSource bsSent = new BindingSource();
        BindingSource bsUnSent = new BindingSource();
        List<SMSContent> buffer = new List<SMSContent>();
        private BackgroundWorker bw = new BackgroundWorker();
        ComposeMessage composeForm;
        private string currentDocument = "Untiled";
        //private int currentModemIndex = -1;
        bool isStarted = false;
        List<GsmModem> lModems;
        private mCore.SMS objSMS = new mCore.SMS();
        List<mCore.SMS> objSmsList = new List<mCore.SMS>();
        int smsProgressCounter = 0;
        List<SMSContent> smsSentList ;
//= new List<SMSContent>();
        private static int smsUniqueKey = 0;
        List<SMSContent> smsUnsentList ;
//= new List<SMSContent>();
        Queue<SMSContent> smsUnsentQueue = new Queue<SMSContent>();
        private int totalSmsCount = 0;

		#endregion Fields 

		#region Constructors (1) 

        public MainForm()
        {
            InitializeComponent();
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            lModems = new List<GsmModem>();

            //comMng = new ComManager();
            this.listViewModems.CheckBoxes = true;
            //this.listViewSMS.Visible = false;
            //this.listViewSMS.RowHeadersVisible = false;
            //this.listViewModems.Visible = false;
            /*
            this.listViewSMS.Columns["obKey"].DisplayIndex = 0;
            this.listViewSMS.Columns["Type"].DisplayIndex = 1;
            this.listViewSMS.Columns["Destination"].DisplayIndex = 2;
            this.listViewSMS.Columns["Content"].DisplayIndex = 3;
            this.listViewSMS.Columns["URL"].DisplayIndex = 4;
            this.listViewSMS.Columns["CreatedDate"].DisplayIndex = 5;
            */
            listViewSMS.DataError += new DataGridViewDataErrorEventHandler(DataGridView1_DataError);
            listViewOutbox.DataError += new DataGridViewDataErrorEventHandler(DataGridView1_DataError);
            //if (this.ribbonTabHome.Active == true)
            //{
            //    this.listViewSMS.Visible = true;

            //}

            //if (this.ribbonTabModems.Active == true)
            //{
            //    this.listViewModems.Visible = true;
            //}
            //this.listViewSMS.Visible = true;
            smsUnsentList = new List<SMSContent>();

            bsUnSent.DataSource = null;
            bsUnSent.DataSource = smsUnsentList;
            
            this.listViewSMS.DataSource = bsUnSent;
            bsUnSent.Clear();
                bsUnSent.ResetBindings(false);
            //currentModemIndex = -1;

            smsSentList = new List<SMSContent>();

            bsSent.DataSource = smsSentList;

            this.listViewOutbox.DataSource = bsSent;
            bsSent.ResetBindings(false);
            this.listViewSMS.Invalidate();

            btnMaxSMS.Text = "Max SMS:" + Environment.NewLine + iMaxSMS;
        }

		#endregion Constructors 

		#region Methods (19) 

		// Public Methods (2) 

        public void on_modem_sending_sms(object sender, SMSSendingEventArgs e)
        {
            return;
            /*
            smsProgressCounter++;
            SMSContent sms = getSmsWithID(e.ID);
            //Console.WriteLine(" ===========>Remove item with index: " + e.ID);
            if (sms != null)
            {
                sms.CreatedDate = DateTime.Now.ToString();

                //if (buffer.Count == 10)
                {
                    //Console.WriteLine(" ===========>Remove item with index: " + e.ID);
                    //smsSentList.AddRange(buffer);
                    smsSentList.Add(sms);
                    smsUnsentList.Remove(sms);
                    //listViewSMS.SuspendLayout();
                    //foreach(SMSContent content in buffer)
                        //smsUnsentList.rem.Remove(content);
                    //smsUnsentList.RemoveAll(x => buffer.Contains(x));
                    //listViewSMS.ResumeLayout();
                    
                    buffer.Clear();
                    //System.Threading.Thread.Sleep(200);
                }
                //else
                {
                //    buffer.Add(sms);
                }
            }
            //if (updating)
                ThreadSafeUpdateUI();
             * */
        }

        public void on_modem_sent_sms(object sender, SMSSentEventArgs e)
        {
            GsmModem modem = sender as GsmModem;
            if (modem == null) return;
            smsProgressCounter++;
            
            // ignore PDU response invalid format because of RSSI signal
            if (e.ErrorCode > 0 && e.ErrorCode != 4018)
            {
                modem.FailedCounter++;
                if (e.ErrorCode == 4012 && false)
                {
                    this.Invoke(
                    new MethodInvoker(
                    delegate()
                    {
                        modem.ChangeState(MODEM_STATE.ERROR_SIM_OUT_OF_MONEY);
                    }));
                }
                //Console.WriteLine("[ERROR: " + e.ErrorCode + "] sent queuesms: " + e.ErrorDescription);
                //modem.siFailed.Text = modem.FailedCounter.ToString();
            }
            else
            {
                modem.SentCounter++;
                //modem.siSentTotal.Text = modem.SentCounter.ToString();

                SMSContent sms = getSmsWithID(e.ID);
                //Console.WriteLine(" ===========>Remove item with index: " + e.ID);
                if (sms != null)
                {
                    sms.CreatedDate = DateTime.Now.ToString();
                    {
                        smsSentList.Add(sms);
                        smsUnsentList.Remove(sms);
                    }
                    //else
                    {
                        //    buffer.Add(sms);
                    }
                }
                
            }
            //if (updating)
            this.Invoke(
                    new MethodInvoker(
                    delegate()
                    {                        
                        modem.updateSMSInfo();
                    }));
            ThreadSafeUpdateUI();

            
        }
		// Private Methods (17) 

        private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs anError)
        {
            if (anError.Context == DataGridViewDataErrorContexts.Display)
            {
                // ignore
                return;
            }

            MessageBox.Show("Error happened " + anError.Context.ToString());

            if (anError.Context == DataGridViewDataErrorContexts.Commit)
            {
                MessageBox.Show("Commit error");
            }
            if (anError.Context == DataGridViewDataErrorContexts.CurrentCellChange)
            {
                MessageBox.Show("Cell change");
            }
            if (anError.Context == DataGridViewDataErrorContexts.Parsing)
            {
                MessageBox.Show("parsing error");
            }
            if (anError.Context == DataGridViewDataErrorContexts.LeaveControl)
            {
                MessageBox.Show("leave control error");
            }

            if ((anError.Exception) is ConstraintException)
            {
                DataGridView view = (DataGridView)sender;
                view.Rows[anError.RowIndex].ErrorText = "an error";
                view.Rows[anError.RowIndex].Cells[anError.ColumnIndex].ErrorText = "an error";

                anError.ThrowException = false;
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (smsSentList.Count == 0 && smsUnsentList.Count == 0)
            {
            }
            else
            {
                // save old document
                switch (MessageBox.Show("Bạn có muốn lưu phần làm việc cũ lại không?",
                    "Lưu dữ liệu",
                    MessageBoxButtons.YesNoCancel,
                    MessageBoxIcon.Question))
                {
                    case DialogResult.Yes:
                        saveDocument();
                        break;
                    case DialogResult.No:
                        break;
                    case DialogResult.Cancel:
                        e.Cancel = true;
                        break;
                }
            }

        }

        private void MainForm_Load(object sender, EventArgs e)
        {
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            //this.listViewSMS.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
            //this.listViewSMS.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
            //this.listViewSMS.Invalidate();
        }

        private void on_btn_compose_clicked(object sender, EventArgs e)
        {
            composeForm = new ComposeMessage();
            DialogResult result = composeForm.ShowDialog();
            if (result == DialogResult.OK)
            {
                if (composeForm.getSMSContentList().Count > 0)
                {
                    btnStart.Enabled = true;
                    btnDelete.Enabled = true;
                }
                foreach (SMSContent content in composeForm.getSMSContentList())
                {
                    smsUniqueKey++;
                    content.ID = smsUniqueKey;
                    smsUnsentQueue.Enqueue(content);
                    content.CreatedDate = DateTime.Now.ToString();
                    smsUnsentList.Add(content);
                    //this.listViewSMS.Invalidate();
                }
                for (int i = 0; i < smsUnsentList.Count ; i++)
                {
                    
                    //    bsUnSent.RemoveAt(i);
                    if (smsUnsentList[i].Content == null || smsUnsentList[i].Type == null)
                        smsUnsentList.RemoveAt(i);
                }
                if (composeForm.MsgMode == ComposeMessage.SMS_TYPE_TEXT)
                    this.listViewSMS.Columns["URL"].Visible = false;
                else
                    this.listViewSMS.Columns["URL"].Visible = true;
                
                // rebinding data to the view
                bsUnSent.ResetBindings(false);
                bsSent.ResetBindings(false);
                // update header text
                /*
                this.listViewSMS.Columns[0].HeaderText = "ID";
                this.listViewSMS.Columns[1].HeaderText = "Kiểu";
                this.listViewSMS.Columns[2].HeaderText = "Tới";
                this.listViewSMS.Columns[3].HeaderText = "Nội Dung";
                this.listViewSMS.Columns[4].HeaderText = "Đường link";
                this.listViewSMS.Columns[5].HeaderText = "Ngày Tạo";*/
                this.listViewSMS.Columns[0].HeaderText = this.listViewSMS.Columns[0].HeaderText;
                this.listViewSMS.Columns[1].HeaderText = this.listViewSMS.Columns[1].HeaderText;
                this.listViewSMS.Columns[2].HeaderText = this.listViewSMS.Columns[2].HeaderText;
                this.listViewSMS.Columns[3].HeaderText = this.listViewSMS.Columns[3].HeaderText;
                this.listViewSMS.Columns[4].HeaderText = this.listViewSMS.Columns[4].HeaderText;
                this.listViewSMS.Columns[5].HeaderText = this.listViewSMS.Columns[5].HeaderText;

                
                updateTabLabel();
                //this.listViewSMS.Invalidate();
            }
        }

        private void on_btn_delete_clicked(object sender, EventArgs e)
        {
            foreach (DataGridViewRow row in this.listViewSMS.SelectedRows)
                if (!row.IsNewRow) this.listViewSMS.Rows.Remove(row);
            updateTabLabel();
        }

        private void on_btn_new_Clicked(object sender, EventArgs e)
        {
            if (smsSentList.Count == 0 && smsUnsentList.Count == 0)
            {
            }
            else
            {
                // save old document
                switch (MessageBox.Show("Bạn có muốn lưu phần làm việc cũ lại không?",
                    "Lưu dữ liệu",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question))
                {
                    case DialogResult.Yes:
                        saveDocument();
                        break;
                    case DialogResult.No:
                        break;
                }
            }
            currentDocument = "Untiled";
            smsUniqueKey = 0;
            smsUnsentList.Clear();
            smsSentList.Clear();
            ThreadSafeUpdateUI();
        }

        private void on_btn_open_clicked(object sender, EventArgs e)
        {
            openFile();
        }

        private void on_btn_save_clicked(object sender, EventArgs e)
        {
            
            saveDocument();
        }

        private void on_btn_start_clicked(object sender, EventArgs e)
        {
            if (lModems.Count == 0)
            {
                MessageBox.Show("Không tìm thấy modem, Hãy cập nhật lại danh sách modem",
                    "Thông tin",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
                return;
            }
            if (smsUnsentList.Count == 0)
            {
                MessageBox.Show("Không có tin nhắn nào trong list!\n Hãy thêm danh sách tin nhắn bằng cách bấm nút \"Soạn tin\"",
                    "Thông tin",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
                return;
            }
            //convertBitarray("*101#");
            //return;
            if (!isStarted)
            {
                btnNew.Enabled = false;
                btnOpen.Enabled = false;
                btnSave.Enabled = false;
                btnCompose.Enabled = false;
                btnDelete.Enabled = false;
                btnUpdate.Enabled = false;
                btnMaxSMS.Enabled = false;

                btnStart.Image = Properties.Resources.Button_Stop_icon;
                btnStart.Text = "Dừng lại";
                isStarted = true;
                listViewSMS.CurrentCell = null;
                //listViewSMS.Rows[0].Selected = false;
                //listViewSMS.Enabled = false;
                smsProgress.Maximum = 100;
                smsProgress.Minimum = 0;
                totalSmsCount = smsUnsentList.Count;
                smsProgressCounter = 0;
                isSendingSms = true;
                sentSMSStart();
                //bw.RunWorkerAsync();
                //@TODO
                // add sending mesage thread here
            }
            else
            {
                btnNew.Enabled = true;
                btnOpen.Enabled = true;
                btnSave.Enabled = true;
                btnCompose.Enabled = true;
                btnDelete.Enabled = true;
                btnUpdate.Enabled = true;
                btnMaxSMS.Enabled = true;

                btnStart.Image = Properties.Resources.Button_Start_icon;
                btnStart.Text = "Bắt đầu";
                isStarted = false;
                isSendingSms = false;
                //listViewSMS.Enabled = true;
                //bw.CancelAsync();
                for (int i = 0; i < lModems.Count; i++)
                {
                    if (lModems[i].smsList.Count <= 0) continue;
                    // stop sending
                    lModems[i].stopSending();
                }
            }
            this.Invalidate();
        }

        private void on_btn_update_modem_clicked(object sender, EventArgs e)
        {
            foreach (string portname in SerialPort.GetPortNames())
            {
                GsmModem modem = new GsmModem(portname);
                if (lModems.Contains(modem))
                    continue;
                this.listViewModems.Items.Add(modem);
                
                lModems.Add(modem);
            }
            this.listViewModems.Refresh();
            updateTabLabel();
            foreach (GsmModem _modem in this.listViewModems.Items)
            //for (int i = 0; i < this.listViewModems.Items.Count;i++)
            {
                //_modem.getCoreObject().QueueSMSSent += new mCore.SMS.QueueSMSSentEventHandler(objSMS_QueueSMSSent);

                if (!_modem.connect())
                {
                    this.listViewModems.Items.Remove(_modem);
                    lModems.Remove(_modem);
                }
            }
            foreach (GsmModem _modem in this.listViewModems.Items)
            {
                // remove all duplicate huawei modem
                if (_modem.Manufacture == "HUAWEI")
                {
                    for (int i = 0; i < lModems.Count; i++)
                        // check imei number
                        if (lModems[i].IMEI == _modem.IMEI)
                        {
                            int lModemPortNumber = 0;
                            int _modemPortNumber = 0;
                            // get modem port number = substring of portname at index 3
                            // COM63 => 63
                            string temp = lModems[i].Portname.Substring(3);
                            lModemPortNumber = int.Parse(lModems[i].Portname.Substring(3));
                            _modemPortNumber = int.Parse(_modem.Portname.Substring(3));
                            if (lModemPortNumber > _modemPortNumber)
                            {
                                this.listViewModems.Items.Remove(_modem);
                                lModems.Remove(_modem);
                                continue;
                            }
                            else
                            {
                                //this.listViewModems.Items.Remove(_modem);
                                lModems[i] = _modem;
                            }
                        }
                }
                _modem.SendingSMS += new GsmModem.SMSSendingEventHandler(on_modem_sending_sms);
                _modem.SentSMS += new GsmModem.SMSSentEventHandler(on_modem_sent_sms);
            }
            
            updateTabLabel();
            this.listViewModems.Refresh();
        }

        private void openFile()
        {
            if (smsSentList.Count == 0 && smsUnsentList.Count == 0)
            {
            }
            else
            {
                // save old document
                switch (MessageBox.Show("Bạn có muốn lưu phần làm việc cũ lại không?",
                    "Lưu dữ liệu",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question))
                {
                    case DialogResult.Yes:
                        saveDocument();
                        break;
                    case DialogResult.No:
                        break;
                }
            }
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Filter = "COM Spammer Project File|*.cpm";
            openFileDialog1.Title = "Mở File";
            openFileDialog1.ShowDialog();
            // If the file name is not an empty string open it for saving.
            if (openFileDialog1.FileName != "")
            {
                this.smsSentList.Clear();
                this.smsUnsentList.Clear();
                
                readDataFromFile(openFileDialog1.FileName);
                currentDocument = openFileDialog1.FileName;
                // rebinding data to the view
                bsUnSent.ResetBindings(false);
                bsSent.ResetBindings(false);
                
                updateTabLabel();
            }
        }

        private void readDataFromFile(string filePath)
        {
            try
            {
                smsUniqueKey = 0;
                XmlDocument xmlDoc = new XmlDocument();
                if (File.Exists(filePath))
                {
                    xmlDoc.Load(filePath);
                    // Locate the root node and 
                    // get a reference to its first child <UNSENT>
                    XmlNode node = xmlDoc.DocumentElement.ChildNodes[0];
                    // Create a list of the child nodes of 
                    // the first node under the root
                    XmlNodeList lstUnsents = node.ChildNodes;
                    bool firstFlag = true;
                    // Visit each node
                    for (int i = 0; i < lstUnsents.Count; i++)
                    {
                        // Look for a node <SMS>
                        if (lstUnsents[i].Name == "SMS")
                        {
                            if (firstFlag)
                            {
                                btnStart.Enabled = true;
                                btnDelete.Enabled = true;

                            }
                            firstFlag = false;
                            // Once/if you find it,
                            // 1. Access its childs
                            // 2. Create a SMSContent object and add to unsent list

                            // Access child nodes
                            XmlNodeList lstSMSAttribute = lstUnsents[i].ChildNodes;
                            // create new sms object based on child node value and add to Unsent list
                            int id = ++smsUniqueKey;//Convert.ToInt32(lstSMSAttribute[0].InnerText); // SMS ID
                            string destination = lstSMSAttribute[1].InnerText;      // SMS destination number
                            string content = lstSMSAttribute[2].InnerText;          // SMS content
                            string url = lstSMSAttribute[3].InnerText;              // SMS url link (optional only in wappush mode)
                            string createdDate = lstSMSAttribute[4].InnerText;      // SMS created date

                            SMSContent sms = null;
                            if (url == "")
                                sms = new SMSContent(Properties.Resources.sms_small, destination, content, url, createdDate);
                            else
                                sms = new SMSContent(Properties.Resources.wap_icon, destination, content, url, createdDate);
                            sms.ID = id;
                            smsUnsentList.Add(sms);
                        }
                    }

                    // get a reference to its second child <SENT>
                    node = xmlDoc.DocumentElement.ChildNodes[1];
                    // Create a list of the child nodes of 
                    // the first node under the root
                    XmlNodeList lstSents = node.ChildNodes;

                    // Visit each node
                    for (int i = 0; i < lstSents.Count; i++)
                    {
                        // Look for a node <SMS>
                        if (lstSents[i].Name == "SMS")
                        {
                            // Once/if you find it,
                            // 1. Access its childs
                            // 2. Create a SMSContent object and add to sent list

                            // Access child nodes
                            XmlNodeList lstSMSAttribute = lstSents[i].ChildNodes;
                            // Create new sms object based on child node value and add to sent list
                            int id = Convert.ToInt32(lstSMSAttribute[0].InnerText); // SMS ID
                            string destination = lstSMSAttribute[1].InnerText;      // SMS destination number
                            string content = lstSMSAttribute[2].InnerText;          // SMS content
                            string url = lstSMSAttribute[3].InnerText;              // SMS url link (optional only in wappush mode)
                            string createdDate = lstSMSAttribute[4].InnerText;      // SMS created date

                            SMSContent sms = null;
                            if (url == "")
                                sms = new SMSContent(Properties.Resources.sms_small, destination, content, url, createdDate);
                            else
                                sms = new SMSContent(Properties.Resources.wap_icon, destination, content, url, createdDate);
                            sms.ID = id;
                            smsSentList.Add(sms);

                        }
                    }
                }
                else
                    MessageBox.Show("File không tồn tại!");
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void saveDocument()
        {
            if (smsUnsentList.Count == 0 && smsSentList.Count == 0)
                return;
            if (currentDocument == "Untiled")
            {
                SaveFileDialog saveFileDialog1 = new SaveFileDialog();
                saveFileDialog1.Filter = "COM Spammer Project File|*.cpm";
                saveFileDialog1.Title = "Lưu thông tin";
                saveFileDialog1.ShowDialog();

                // If the file name is not an empty string open it for saving.
                if (saveFileDialog1.FileName != "")
                {
                    writeDataToFile(saveFileDialog1.FileName);
                }
            }
            else
            {
                writeDataToFile(currentDocument);
            }
        }

        private void TabControl1_Selected(Object sender, TabControlEventArgs e)
        {
            
            if (e.TabPageIndex == 0)
            {
                btnDelete.Enabled = true;
                //MessageBox.Show("1");
            }
            if (e.TabPageIndex == 1)
            {
                btnDelete.Enabled = false;
                //MessageBox.Show("1");
            }
            if (e.TabPageIndex == 2)
            {
                btnDelete.Enabled = false;
                //MessageBox.Show("1");
            }
        }

        private void update_Modem_click(object sender, EventArgs e)
        {
        }

        private void writeDataToFile(string filePath)
        {
            /*
                 * <?xml version="1.0"?>
	             *  <!--COM Spammer Project file version 1.0-->
                 *  <UNSENT>
                 *      <SMS>
                 *          <ID> id value </ID>
                 *          <TYPE> type </TYPE>
                 *          <DESTINATION> value </DESTINATION>
                 *          <CONTENT> value </CONTENT>
                 *          <URL> value </URL>
                 *          <DATE> value </DATE>
                 *      </SMS>
                 *      <SMS>
                 *          ...
                 *      </SMS>
                 *  </UNSENT>
                 *  <SENT>
                 *      <SMS>
                 *          <ID> id value </ID>
                 *          <TYPE> type </TYPE>
                 *          <DESTINATION> value </DESTINATION>
                 *          <CONTENT> value </CONTENT>
                 *          <URL> value </URL>
                 *          <DATE> value </DATE>
                 *      </SMS>
                 *      <SMS>
                 *          ...
                 *      </SMS
                 *  </SENT>
                 *  */
                XmlTextWriter textWriter = new XmlTextWriter(filePath, null);
                // Opens the document
                textWriter.WriteStartDocument();
                // Write comments
                textWriter.WriteComment("COM Spammer Project file version 1.0");
                textWriter.WriteStartElement("Project");
                // Write first element 
                textWriter.WriteStartElement("UNSENT");
                int unsentCount = smsUnsentList.Count;
                for (int i = 0; i < unsentCount; i++)
                {
                    // write sms node
                    textWriter.WriteStartElement("SMS");

                    // write ID sub node
                    textWriter.WriteStartElement("ID");
                    // write value
                    textWriter.WriteValue(smsUnsentList[i].ID);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("DESTINATION");
                    // write value
                    textWriter.WriteValue(smsUnsentList[i].Destination);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("CONTENT");
                    // write value
                    textWriter.WriteValue(smsUnsentList[i].Content);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("URL");
                    // write value
                    textWriter.WriteValue(smsUnsentList[i].URL);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("DATE");
                    // write value
                    textWriter.WriteValue(smsUnsentList[i].CreatedDate);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // end of sms element
                    textWriter.WriteEndElement();
                }
                textWriter.WriteEndElement();
                // Write second element 
                textWriter.WriteStartElement("SENT");
                int sentCount = smsSentList.Count;
                for (int i = 0; i < sentCount; i++)
                {
                    // write sms node
                    textWriter.WriteStartElement("SMS");

                    // write ID sub node
                    textWriter.WriteStartElement("ID");
                    // write value
                    textWriter.WriteValue(smsSentList[i].ID);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("DESTINATION");
                    // write value
                    textWriter.WriteValue(smsSentList[i].Destination);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("CONTENT");
                    // write value
                    textWriter.WriteValue(smsSentList[i].Content);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("URL");
                    // write value
                    textWriter.WriteValue(smsSentList[i].URL);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // write ID sub node
                    textWriter.WriteStartElement("DATE");
                    // write value
                    textWriter.WriteValue(smsSentList[i].CreatedDate);
                    // end of sms element
                    textWriter.WriteEndElement();

                    // end of sms element
                    textWriter.WriteEndElement();
                }
                textWriter.WriteEndElement();
                textWriter.WriteEndElement();
                // Ends the document.
                textWriter.WriteEndDocument();
                // close writer
                textWriter.Close();
        }

		#endregion Methods 



        #region background worker
        private bool isSendingSms = false;

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            
            //this.listViewSMS.Enabled = false;
            //this.listViewOutbox.Enabled = false;
            //this.listViewSMS.ClearSelection();
            //this.listViewOutbox.ClearSelection();
            isSendingSms = true;//for first time sending sms
            int modemCount = lModems.Count;
            int smsCount = smsUnsentList.Count;
            int smsPerModem = smsCount / modemCount;
            //int mod = smsCount % modemCount;
            
            //List<SMSContent>[] modemSmsList = new List<SMSContent>[modemCount];
            
            for (int i = 0; i < modemCount-1; i++)
            {
                lModems[i].smsList.Clear();
                lModems[i].smsMap.Clear();
                lModems[i].smsList.AddRange((List<SMSContent>)smsUnsentList.GetRange(i * smsPerModem, smsPerModem));
                
            }
            lModems[modemCount - 1].smsList.Clear();
            lModems[modemCount - 1].smsMap.Clear();
            lModems[modemCount - 1].smsList.AddRange((List<SMSContent>)smsUnsentList.GetRange((modemCount - 1) * smsPerModem, smsCount - (modemCount - 1) * smsPerModem));

            for (int i = 0; i < modemCount; i++)
            {
                if ((worker.CancellationPending == true) )
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    if (lModems[i].smsList.Count <= 0) continue;

                    //mut.WaitOne();
                    // create new thread for each modem to send list sms.
                    //object args = new object[1] { i };
                    //(new System.Threading.Thread(new ParameterizedThreadStart(coreSendSmsWork))).Start(args);
                    //mut.ReleaseMutex();
                    lModems[i].sendMessageList();
                }
            }
            /*
            int temp = -1;
            smsProgressCounter = 1;
            while (isStarted) {
                if (temp != smsProgressCounter)
                {
                    bw.ReportProgress((smsProgressCounter * 100 / smsCount));
                    temp = smsProgressCounter;
                }
            };*/
        }
        private void sentSMSStart()
        {

            int modemCount = lModems.Count;
            int smsCount = smsUnsentList.Count;
            int smsPerModem = smsCount / modemCount;
            //int mod = smsCount % modemCount;

            //List<SMSContent>[] modemSmsList = new List<SMSContent>[modemCount];

            for (int i = 0; i < modemCount - 1; i++)
            {
                lModems[i].smsList.Clear();
                lModems[i].smsMap.Clear();
                if (smsPerModem > iMaxSMS)
                    lModems[i].smsList.AddRange((List<SMSContent>)smsUnsentList.GetRange(i * iMaxSMS, iMaxSMS));
                else
                    lModems[i].smsList.AddRange((List<SMSContent>)smsUnsentList.GetRange(i * smsPerModem, smsPerModem));

            }
            lModems[modemCount - 1].smsList.Clear();
            lModems[modemCount - 1].smsMap.Clear();
            if (smsCount - (modemCount - 1) * iMaxSMS > iMaxSMS && smsPerModem > iMaxSMS)
                lModems[modemCount - 1].smsList.AddRange((List<SMSContent>)smsUnsentList.GetRange((modemCount - 1) * iMaxSMS, iMaxSMS));
            else if (smsCount - (modemCount - 1) * iMaxSMS <= iMaxSMS && smsPerModem > iMaxSMS)
                lModems[modemCount - 1].smsList.AddRange((List<SMSContent>)smsUnsentList.GetRange((modemCount - 1) * iMaxSMS, smsCount - (modemCount - 1) * iMaxSMS));
            else
                lModems[modemCount - 1].smsList.AddRange((List<SMSContent>)smsUnsentList.GetRange((modemCount - 1) * smsPerModem, smsCount - (modemCount - 1) * smsPerModem));

            for (int i = 0; i < modemCount; i++)
            {
                // if there is no more sms in modem's list, dont send
                if (lModems[i].smsList.Count <= 0) continue;
                // call modem send sms method
                lModems[i].sendMessageList();
            }
        }
        private void updateTabLabel()
        {
            if (smsUnsentList.Count > 0)
                this.tabSMS.Text = "Tin nhắn(" + smsUnsentList.Count + ")";
            else
                this.tabSMS.Text = "Tin nhắn";
            if (lModems.Count > 0)
                this.tabModem.Text = "Modems (" + lModems.Count + ")";
            else
                this.tabModem.Text = "Modems";
            if (smsSentList.Count > 0)
                this.tabSent.Text = "Thư đã gửi(" + smsSentList.Count + ")";
            else
                this.tabSent.Text = "Thư đã gửi";
        }
        bool updating = false;
        SMSContent getSmsWithID(int id)
        {
            foreach(SMSContent content in smsUnsentList)
                if (content.ID == id)
                    return content;
            return null;
        }

        private void ThreadSafeUpdateUI()
        {
            if (this.InvokeRequired)
            {
                try
                {
                    this.Invoke(
                        new MethodInvoker(
                        delegate() { ThreadSafeUpdateUI(); }));
                }
                catch (Exception e)
                { Console.WriteLine("Exception object: " + e.Message); }
            }
            else
            {
                try
                {
                    updating = true;
                    //use intval and boolval
                    this.listViewSMS.ClearSelection();
                    //if (ribbonTabHome.Active)
                    {
                        bsUnSent.ResetBindings(false);
                        // update header text
                        /*
                        this.listViewSMS.Columns[0].HeaderText = "ID";
                        this.listViewSMS.Columns[1].HeaderText = "Kiểu";
                        this.listViewSMS.Columns[2].HeaderText = "Tới";
                        this.listViewSMS.Columns[3].HeaderText = "Nội Dung";
                        //this.listViewSMS.Columns[4].HeaderText = "Đường link";
                        this.listViewSMS.Columns[4].HeaderText = "Ngày Tạo";*/
                        //this.listViewSMS.CurrentCell = this.listViewSMS.Rows[0].Cells[0];
                    }
                    

                    //if (ribbonTabSentbox.Active)
                    {
                        this.listViewOutbox.ClearSelection();

                        bsSent.ResetBindings(false);
                        // update header text
                        /*
                        this.listViewOutbox.Columns[0].HeaderText = "Kiểu";
                        this.listViewOutbox.Columns[1].HeaderText = "Tới";
                        this.listViewOutbox.Columns[2].HeaderText = "Nội Dung";
                        this.listViewOutbox.Columns[3].HeaderText = "Đường link";
                        this.listViewOutbox.Columns[4].HeaderText = "Ngày Tạo";
                         * */
                    }
                    if (smsProgressCounter >= totalSmsCount && totalSmsCount > 0)
                    {
                        btnNew.Enabled = true;
                        btnOpen.Enabled = true;
                        btnSave.Enabled = true;
                        btnCompose.Enabled = true;
                        btnDelete.Enabled = true;
                        btnUpdate.Enabled = true;
                        btnMaxSMS.Enabled = true;
                        smsProgress.Value = smsProgress.Maximum;
                        btnStart.Image = Properties.Resources.Button_Start_icon;
                        btnStart.Text = "Bắt đầu";
                        isStarted = false;
                        smsProgressCounter = 0;
                        totalSmsCount = 0;
                        isSendingSms = false;
                        //listViewSMS.Enabled = true;
                        //bw.CancelAsync();
                        for (int i = 0; i < lModems.Count; i++)
                        {
                            if (lModems[i].smsList.Count <= 0) continue;
                            // stop sending
                            lModems[i].stopSending();
                        }
                    }
                    else
                    {
                        if (totalSmsCount > 0)
                        {
                            smsProgress.Value = (smsProgressCounter * 100 / totalSmsCount);
                        }
                    }
                    smsProgress.Refresh();
                    updateTabLabel();
                    
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.StackTrace);
                }
                finally
                {
                    updating = false;
                }
            }
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            if ((e.Cancelled == true))
            {
                //this.tbProgress.Text = "Canceled!";
                int modemCount = lModems.Count;
                for (int i = 0; i < modemCount; i++)
                {

                        if (lModems[i].smsList.Count <= 0) continue;

                        //mut.WaitOne();
                        // create new thread for each modem to send list sms.
                        //object args = new object[1] { i };
                        //(new System.Threading.Thread(new ParameterizedThreadStart(coreSendSmsWork))).Start(args);
                        //mut.ReleaseMutex();
                        lModems[i].stopSending();
                }
                ThreadSafeUpdateUI();
                smsProgress.Value = 0;
                MessageBox.Show("Đã huỷ");
            }
            else if (!(e.Error == null))
            {
                //this.tbProgress.Text = ("Error: " + e.Error.Message);
                smsProgress.Value = 0;
                MessageBox.Show("Có lỗi xảy ra: " + e.Error.StackTrace);
            }
            else
            {
                smsProgress.Value = 100;
                //MessageBox.Show("Hoàn Thành! Tất cả tin nhắn đã được gửi xong.");
                smsProgress.Value = 0;
            }
            //this.listViewSMS.DataSource = null;
            //initSMSHeader();
            //this.listViewSMS.DataSource = smsUnsentList;
            smsSentList.AddRange(buffer);
            //smsSentList.Add(sms);
            foreach (SMSContent content in buffer)
                smsUnsentList.Remove(content);
            buffer.Clear();
            btnStart.Image = Properties.Resources.Button_Start_icon;
            btnStart.Text = "Bắt đầu";
            isStarted = false;
            //this.listViewSMS.Enabled = true;
            //this.listViewOutbox.Enabled = true;
            //ThreadSafeUpdateUI();
        }
        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%");
            if (e.ProgressPercentage > smsProgress.Maximum)
                smsProgress.Value = 100;
            else
                smsProgress.Value = e.ProgressPercentage;
            //ThreadSafeUpdateUI();
        }
        #endregion

        public static DialogResult InputBox(string title, string promptText, ref int value)
        {
            Form form = new Form();
            Label label = new Label();
            NumericUpDown numerBox = new NumericUpDown();
            Button buttonOk = new Button();
            Button buttonCancel = new Button();

            form.Text = title;
            label.Text = promptText;
            numerBox.Minimum = 1;
            numerBox.Maximum = 1000;
            numerBox.Value = value;

            buttonOk.Text = "OK";
            buttonCancel.Text = "Cancel";
            buttonOk.DialogResult = DialogResult.OK;
            buttonCancel.DialogResult = DialogResult.Cancel;

            label.SetBounds(10, 20, 220, 13);
            numerBox.SetBounds(10, 40, 50, 20);
            buttonOk.SetBounds(70, 40, 75, 23);
            buttonCancel.SetBounds(150, 40, 75, 23);

            label.AutoSize = true;
            numerBox.Anchor = numerBox.Anchor | AnchorStyles.Right;
            buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

            form.ClientSize = new System.Drawing.Size(250, 80);
            form.Controls.AddRange(new Control[] { label, numerBox, buttonOk, buttonCancel });
            form.ClientSize = new System.Drawing.Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.StartPosition = FormStartPosition.CenterScreen;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.AcceptButton = buttonOk;
            form.CancelButton = buttonCancel;

            DialogResult dialogResult = form.ShowDialog();
            value = (int)numerBox.Value;
            return dialogResult;
        }

        private void on_btn_maxsms_clicked(object sender, EventArgs e)
        {
            int value = iMaxSMS;
            if (InputBox("Cài đặt", "Nhập vào số tin nhắn tối đa modem có thể gửi:", ref value) == DialogResult.OK)
            {
                iMaxSMS = value;
                btnMaxSMS.Text = "Max SMS" + Environment.NewLine + iMaxSMS;
            }
        }
        private int iMaxSMS = 50;
    }
}
